package de.codi.string.metrics;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import de.codi.string.StringPreparation;
import de.codi.string.StringSimilarity;

public class JakobTimoSim implements StringSimilarity {
	@Override
	public double getSim(String a, String b) {
		if (a.equals(b)) {
			return 1.0;
		} else if (a.length() == 1 && b.length() == 1) {
			return 0.0;
		}
		Set<String> aS = getWords(a);
		Set<String> bS = getWords(b);
		aS.remove("");
		aS.remove(" ");
		bS.remove("");
		bS.remove(" ");
		int n = 0;
		// Anfang: ab - a b
		if (aS.size() == 1 && bS.size() != 1) {
			int l = 0;
			for (String s : bS) {
				if (a.contains(s)) {
					n++;
					l += s.length();
				}
			}
			if (bS.size() == n && Math.abs(a.length() - l) < 2) {
				return 1.0;
			}
		}
		n = 0;
		if (bS.size() == 1 && aS.size() != 1) {
			int l = 0;
			for (String s : aS) {
				if (b.contains(s)) {
					n++;
					l += s.length();
				}
			}
			if (aS.size() == n && Math.abs(b.length() - l) < 2) {
				return 1.0;
			}
		}
		// Ende
		
		// a b c = ab c
		if (a.replaceAll(" ", "").length() == b.replaceAll(" ", "").length() &&  Math.abs(aS.size() - bS.size()) == 1){
			HashSet<String> both = new HashSet<String>();
			both.addAll(aS);
			both.addAll(bS);
			HashSet<String> temp = new HashSet<String>();
			for (String s : both){
				if (aS.contains(s) && bS.contains(s)){
					temp.add(s);
				}
			}
			both.removeAll(temp);
			if (both.size() == 3){
				List<String> three = new ArrayList<String>(both);
				if (three.get(0).contains(three.get(1)) && three.get(0).contains(three.get(2))){
					return 1.0;
				}
				if (three.get(1).contains(three.get(0)) && three.get(1).contains(three.get(2))){
					return 1.0;
				}
				if (three.get(2).contains(three.get(0)) && three.get(2).contains(three.get(1))){
					return 1.0;
				}
			} 
		}
		
		n = 0;
		HashSet<String> blockA = new HashSet<String>();
		HashSet<String> blockB = new HashSet<String>();
		int none = Math.min(aS.size(), bS.size()) / 2;
		for (String s : aS) {
			if (bS.contains(s) && !blockA.contains(s) && !blockB.contains(s)) {
				blockA.add(s);
				blockB.add(s);
				n++;
			} else if (none > 0 && aS.size() >= 2 && bS.size() >= 2) {
				for (String s2 : bS) {
					if ((Math.abs(s.length() - s2.length()) <= 3) && checkStart(s, s2) >= 0.75 && !blockB.contains(s2)) {
						blockA.add(s);
						blockB.add(s2);
						n++;
						none--;
						break;
					}
				}
			}
		}
		if (n == bS.size() && n == aS.size()) {
			if (none == Math.min(aS.size(), bS.size())/2){
				return 1.0;
			} else {
				return 0.8; // 0.95
			}
			
		} else if (n == bS.size() || n == aS.size())  {
			if ((n > 1 || (n == 1 && none > 0)) &&((float) (Math.min(aS.size(), bS.size())) / Math.max(aS.size(), bS.size())) > 0.7 )
				return 0.7; //0.9
			
			if (Math.abs(a.replaceAll(" ", "").length() - b.replaceAll(" ", "").length()) <= Math.abs(aS.size()-bS.size()) 
					&& none == Math.min(aS.size(), bS.size()) / 2){
				Set<String> longSet = new HashSet<String>();
				if (aS.size()>bS.size()){
					longSet.addAll(aS);
				}
				else {
					longSet.addAll(bS);
				}
				for (String s : longSet){
					if(!StringPreparation.isNotNumber(s))
						return 0.0;
				}
				
				return 0.5; // 0.89
			}
		} else if (bS.size() == aS.size() && (float)n/aS.size()>=0.8 ){
				return 0.6; // 0.89
		}

		return 0.0;
	}

	@Override
	public Integer getID() {
		return new Integer(7);
	}

	private Set<String> getWords(String s) {
		String[] temp = s.split(" ");
		Set<String> set = new HashSet<String>();
		for (int i = 0; i < temp.length; i++) {
			set.add(temp[i]);
		}
		return set;
	}

	private double checkStart(String a, String b) {
		String shortString, longString;
		if (a.length() <= b.length()) {
			shortString = a;
			longString = b;
		} else {
			shortString = b;
			longString = a;
		}
		int n = (int) Math.max(3, Math.ceil((float) shortString.length() / 2));
		if (shortString.length() > n) {
			String sub = shortString.substring(0, n);
			if (longString.startsWith((sub))) {
				return 1.0;
			}
		}
		if (shortString.length() > 2 && longString.startsWith((shortString.substring(0, 2)))) {
			return new LevenshteinSim().getSim(shortString, longString);
		} else if (longString.startsWith(shortString)) {
			return 1.0;
		}
		return 0.0;
	}

}
